package main

import (
	"log"
	"net"
	"os"
	"sync"

	"gitee.com/viplianghl/golib/liangtcp"
	"github.com/jinzhu/configor"
)

var g_conn net.Conn
var g_listenStr string
var g_connStr string

var g_mutex sync.Mutex

// ---------------------------------------------handle server msg

func onDisconn(conn net.Conn) error {
	g_mutex.Lock()
	defer g_mutex.Unlock()

	// close server conn
	if g_conn != nil {
		g_conn.Close()
		g_conn = nil
	}
	return nil
}

func onMsg(conn net.Conn, buf []byte) error {
	// log.Println("reve data (from ", conn.RemoteAddr().String(), "): ", string(buf))

	// send to client
	g_mutex.Lock()
	defer g_mutex.Unlock()

	if g_conn != nil {
		n, err := g_conn.Write(buf)
		if err != nil {
			log.Printf("trans send failed (n=%d)(err=%s)\r\n", n, err.Error())
			return err
		}
	}

	return nil
}

// ---------------------------------------------handle client msg

func handleClientMsg(conn net.Conn) {
	// log.Println("LiangTCP connected: ", conn.RemoteAddr().String())
	if g_conn != nil {
		log.Println("another client coming, we just can't server any more")
		conn.Close()
		return
	}
	g_conn = conn
	defer onDisconn(conn)

	// init server connection
	var tcpServer liangtcp.LiangTCPClient
	tcpServer.AESKey = []byte(Config.AESKey)
	tcpServer.OnDisconn = onDisconn
	tcpServer.OnMsg = onMsg
	err := tcpServer.Connect(g_connStr)
	if err != nil {
		log.Println("connnect to server failed: ", g_connStr, err.Error())
		return
	}
	log.Println("a client coming, we just connected to ", g_connStr)

	for {
		// 接收
		buf := make([]byte, 1600)
		n, err1 := g_conn.Read(buf)
		if err1 != nil {
			log.Printf("read error(from %s): %s\r\n", conn.RemoteAddr().String(), err1.Error())
			break
		}
		// log.Printf("LiangTCP read %d bytes(from %s\r\n", n, conn.RemoteAddr().String())

		// 转发给服务端
		tcpServer.SendMsg(buf[:n])
	}
}

// ---------------------------------------------main
func pressanykey() {
	log.Println("press Enter to exit...")
	//var c byte
	//fmt.Scan(&c)
	n := make([]byte, 1)
	os.Stdin.Read(n)
}

var Config = struct {
	Listenstr string `required:"true"`
	Connstr   string `required:"true"`
	AESKey    string `required:"true"`
}{}

func main() {

	configor.Load(&Config, "./config.yml")
	// check args
	if len(os.Args) < 2 {
		log.Println("use conf.yml Args: ", Config)
		g_listenStr = Config.Listenstr
		g_connStr = Config.Connstr
	} else {
		g_listenStr = os.Args[1]
		g_connStr = os.Args[2]
	}

	// init
	g_conn = nil

	// listen
	l, err := net.Listen("tcp", g_listenStr)
	if err != nil {
		log.Println("listen err: ", err.Error())
		pressanykey()
		return
	}
	defer l.Close()
	log.Println("listen at ", g_listenStr)

	for {
		conn, err1 := l.Accept()
		if err1 != nil {
			log.Println("accept err: ", err1.Error())
			break
		}
		go handleClientMsg(conn)
	}
	pressanykey()
}
